import os
import wx

from utils import tracer
from gui.toolbar import Toolbar
from documentPane import DocumentsPane
from configPane import ConfigPane
from plugins.base import plugin
from utils.eventHandler import EventHandler, EventArgs

class DocumentManager(plugin.Plugin):
  def __init__(self):
    plugin.Plugin.__init__(self)

    self._documentChangedEventHandler = EventHandler()
    self._documentNameChangedEventHandler = EventHandler()

  def uninit(self):
    self.closeAll()
  
  def createPane(self):
    if self._mainFrm is None:
      return None
    pane = DocumentsPane(self._mainFrm)
    pane.documentChangedEventHandler(self.onDocumentChanged)
    pane.documentNameChangedEventHandler(self.onDocumentNameChanged)
    return pane
  
  def createConfigPane(self):
    if self._mainFrm is None:
      return None
    return ConfigPane(self._mainFrm)
  
  def createMenus(self):
    if self._mainFrm is None:
      return None
    
    menus = []
  
    # create file menu
    file_menu = wx.Menu()
    
    file_menu_item_new = file_menu.Append(-1, '&New')
    self._mainFrm.Bind(wx.EVT_MENU, self.onNewFile, file_menu_item_new)
    
    file_menu_item_open = file_menu.Append(-1, '&Open')
    self._mainFrm.Bind(wx.EVT_MENU, self.onOpenFile, file_menu_item_open)

    file_menu_item_separator_1 = file_menu.AppendSeparator()

    file_menu_item_save = file_menu.Append(-1, '&Save')
    self._mainFrm.Bind(wx.EVT_MENU, self.onSaveFile, file_menu_item_save)

    file_menu_item_save_as = file_menu.Append(-1, 'Save &As')  
    self._mainFrm.Bind(wx.EVT_MENU, self.onSaveFileAs, file_menu_item_save_as)
  
    file_menu_item_save_all = file_menu.Append(-1, 'Save All')
    self._mainFrm.Bind(wx.EVT_MENU, self.onSaveAllFiles, file_menu_item_save_all)

    file_menu_item_separator_2 = file_menu.AppendSeparator()

    file_menu_item_close = file_menu.Append(-1, 'Close')
    self._mainFrm.Bind(wx.EVT_MENU, self.onCloseFile, file_menu_item_close)

    file_menu_item_close_all = file_menu.Append(-1, 'Close All')
    self._mainFrm.Bind(wx.EVT_MENU, self.onCloseAllFiles, file_menu_item_close_all)

    file_menu_item_separator_3 = file_menu.AppendSeparator()

    menus.append(('&File', file_menu))

    # create edit menu
    edit_menu = wx.Menu()

    edit_menu_item_cut = edit_menu.Append(-1, 'Cu&t')
    self._mainFrm.Bind(wx.EVT_MENU, self.onIndent, edit_menu_item_cut)

    edit_menu_item_copy = edit_menu.Append(-1, '&Copy')
    self._mainFrm.Bind(wx.EVT_MENU, self.onIndent, edit_menu_item_copy)

    edit_menu_item_paste = edit_menu.Append(-1, '&Paste')
    self._mainFrm.Bind(wx.EVT_MENU, self.onIndent, edit_menu_item_paste)

    edit_menu_item_delete = edit_menu.Append(-1, '&Delete')
    self._mainFrm.Bind(wx.EVT_MENU, self.onIndent, edit_menu_item_delete)

    edit_menu_item_separator_1 = edit_menu.AppendSeparator()

    edit_menu_item_indent = edit_menu.Append(-1, 'Indent Region')
    self._mainFrm.Bind(wx.EVT_MENU, self.onIndent, edit_menu_item_indent)
    
    edit_menu_item_unindent = edit_menu.Append(-1, 'Unindent Region')
    self._mainFrm.Bind(wx.EVT_MENU, self.onUnindent, edit_menu_item_unindent)

    edit_menu_item_comment = edit_menu.Append(-1, 'Comment Region')
    self._mainFrm.Bind(wx.EVT_MENU, self.onComment, edit_menu_item_comment)
    
    edit_menu_item_uncomment = edit_menu.Append(-1, 'Uncomment Region')
    self._mainFrm.Bind(wx.EVT_MENU, self.onUncomment, edit_menu_item_uncomment)

    edit_menu_item_separator_2 = edit_menu.AppendSeparator()

    edit_menu_item_fold_all = edit_menu.Append(-1, 'Fold All')
    self._mainFrm.Bind(wx.EVT_MENU, self.onFoldAll, edit_menu_item_fold_all)
    
    edit_menu_item_expand_all = edit_menu.Append(-1, 'Expand All')
    self._mainFrm.Bind(wx.EVT_MENU, self.onExpandAll, edit_menu_item_expand_all)

    edit_menu_item_separator_3 = edit_menu.AppendSeparator()

    menus.append(('&Edit', edit_menu))

    # add accelerator table
    aTable = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('S'), file_menu_item_save.GetId()), 
                                  (wx.ACCEL_CTRL, ord('I'), edit_menu_item_indent.GetId()),
                                  (wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('I'), edit_menu_item_unindent.GetId()),
                                  (wx.ACCEL_CTRL, ord('M'), edit_menu_item_comment.GetId()),
                                  (wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('M'), edit_menu_item_uncomment.GetId()),
                                  (wx.ACCEL_CTRL, ord('O'), edit_menu_item_fold_all.GetId()),
                                  (wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('O'), edit_menu_item_expand_all.GetId())])
    self._mainFrm.SetAcceleratorTable(aTable)
  
    return menus
  
  def createToolbar(self):
    if self._mainFrm is None:
      return None
    
    iconSize = wx.Size(16, 16)
    toolbar = Toolbar(self._mainFrm, 'docsToolbar', 'Documents')
    toolbar.SetToolBitmapSize(wx.Size(20, 20))
  
    # add new button
    bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(10, "New", bmp)
    toolbar.Bind(wx.EVT_TOOL, self.onNewFile, id=10)
    
    # add open button
    bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(20, "Open", bmp)
    toolbar.Bind(wx.EVT_TOOL, self.onOpenFile, id=20)
    
    # add save button
    bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(30, "Save", bmp)
    toolbar.Bind(wx.EVT_TOOL, self.onSaveFile, id=30)
    
    # add save as button
    bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(40, "Save As", bmp)
    toolbar.Bind(wx.EVT_TOOL, self.onSaveFileAs, id=40)
    
    # add save all button
    bmp = wx.ArtProvider.GetBitmap(wx.ART_FLOPPY, wx.ART_TOOLBAR, iconSize)
    toolbar.AddLabelTool(50, "Save All", bmp)
    toolbar.Bind(wx.EVT_TOOL, self.onSaveAllFiles, id=50)

    if wx.Platform == '__WXMSW__':
      # add separator
      toolbar.AddSeparator()
  
      # add cut button
      bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(60, "Cut", bmp)
      toolbar.Bind(wx.EVT_TOOL, self.onCut, id=60)
  
      # add copy button
      bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(70, "Copy", bmp)
      toolbar.Bind(wx.EVT_TOOL, self.onCopy, id=70)
  
      # add paste button
      bmp = wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(80, "Paste", bmp)
      toolbar.Bind(wx.EVT_TOOL, self.onPaste, id=80)
  
      # add delete button
      bmp = wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(90, "Delete", bmp)
      toolbar.Bind(wx.EVT_TOOL, self.onDelete, id=90)
  
      # add separator
      toolbar.AddSeparator()
  
      # indent
      bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
      toolbar_item_indent = toolbar.AddLabelTool(100, "Indent", bmp, bmp, wx.ITEM_NORMAL, 'Indent Selections')
      toolbar.Bind(wx.EVT_TOOL, self.onIndent, id=100)
  
      # unindent
      bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
      toolbar_item_unindent = toolbar.AddLabelTool(110, "Unindent", bmp, bmp, wx.ITEM_NORMAL, 'Unindent Selections')
      toolbar.Bind(wx.EVT_TOOL, self.onUnindent, id=110)
  
      # comment
      bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(120, "Comment", bmp, bmp, wx.ITEM_NORMAL, 'Comment Selections')
      toolbar.Bind(wx.EVT_TOOL, self.onComment, id=120)
  
      # uncomment
      bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, iconSize)
      toolbar.AddLabelTool(130, "Uncomment", bmp, bmp, wx.ITEM_NORMAL, 'Uncomment Selections')
      toolbar.Bind(wx.EVT_TOOL, self.onUncomment, id=130)

    toolbar.Realize()
    return toolbar
  
  # -- Methods -------------------------------------------------------------------
  def newFile(self):
    pane = self.getPane()
    if not pane is None:
      pane.newDocument()
  
  def openFile(self, filename=''):
    pane = self.getPane()
    if not pane is None:
      pane.openDocument(filename)
  
  def saveFile(self):
    pane = self.getPane()
    if not pane is None:
      pane.saveDocument()
  
  def saveFileAs(self, filename=''):
    pane = self.getPane()
    if not pane is None:
      pane.saveDocumentAs(filename)
  
  def saveAll(self):
    pane = self.getPane()
    if not pane is None:
      pane.saveAll()
  
  def closeFile(self):
    pane = self.getPane()
    if not pane is None:
      pane.closeDocument()
  
  def closeAll(self):
    pane = self.getPane()
    if not pane is None:
      pane.closeAll()
  
  def gotoLine(self, lineNo=0):
    pane = self.getPane()
    if not pane is None:
      pane.gotoDocumentLine(lineNo)
  
  def getCurrentDocument(self):
    pane = self.getPane()
    if not pane is None:
      return pane.getCurrentDocument()
    return None

  # -- Event Handlers --------------------------------------------------------------
  def documentChangedEventHandler(self, handler):
    self._documentChangedEventHandler.add(handler)
  def onInnerDocumentChanged(self, document):
    eventArgs = EventArgs((document,))
    self._documentChangedEventHandler.invoke(self, eventArgs)

  def documentNameChangedEventHandler(self, handler):
    self._documentNameChangedEventHandler.add(handler)
  def onInnerDocumentNameChanged(self, document):
    eventArgs = EventArgs((document,))
    self._documentNameChangedEventHandler.invoke(self, eventArgs)

  # -- Pane Events -----------------------------------------------------------------
  def onDocumentChanged(self, sender, args):
    self.onInnerDocumentChanged(args.getValue()[0])

  def onDocumentNameChanged(self, sender, args):
    self.onInnerDocumentNameChanged(args.getValue()[0])
  
  # -- Event Processers ------------------------------------------------------------
  def onNewFile(self, evt):
    self.newFile()
  
  def onOpenFile(self, evt):
    self.openFile()
  
  def onSaveFile(self, evt):
    self.saveFile()
  
  def onSaveFileAs(self, evt):
    self.saveFileAs()
  
  def onSaveAllFiles(self, evt):
    self.saveAll()
  
  def onCloseFile(self, evt):
    self.closeFile()
  
  def onCloseAllFiles(self, evt):
    self.closeAll()
  
  def onCut(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.cut()
  
  def onCopy(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.copy()
  
  def onPaste(self, evt):    
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.paste()
  
  def onDelete(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.delete()
  
  def onIndent(self, evt):    
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.indentSelection()
  
  def onUnindent(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.unindentSelection()
  
  def onComment(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.comment()
  
  def onUncomment(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.uncomment()
  
  def onFoldAll(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.foldAll()
  
  def onExpandAll(self, evt):  
    docsPane = self.getPane()
    if docsPane is None:
      return
  
    curDoc = docsPane.getCurrentDocument()
    if curDoc is None:
      return
  
    editor = curDoc.getEditor()
    if editor is None:
      return
  
    editor.expandAll()



instance = None
def getInstance():
  global instance
  if instance is None:
    instance = createInstance()
  return instance

def createInstance():
  return DocumentManager()

